#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
    // version 2
    using namespace CondModule;
    using namespace LockModule;
    static const int gcap = 10;
    template <class T>
    class BlockQueue
    {
    private:
        bool IsFull() { return _q.size() == _cap; }
        bool IsEmpty() { return _q.empty(); }

    public:
        BlockQueue(int cap = gcap) : _cap(cap), _cwait_num(0), _pwait_num(0)
        {
        }
        void Equeue(const T &in)
        {
            // pthread_mutex_lock(&_mutex);
            LockGuard lockguard(_mutex);
            // 你想放就能放吗，生产数据是有条件的------阻塞队列不为满
            while (IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                _pwait_num++;
                _productor_cond.Wait(_mutex); // 我们在临界区中等待是必然的
                _pwait_num--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            // 走到这里，就是if(IsFUll())不满足 || 线程被唤醒
            _q.push(in); // 生产
            // 走到这，肯定有数据
            if (_cwait_num) // 阻塞队列里有消费者等待
            {
                std::cout << "唤醒消费者" << std::endl;
                _consumer_cond.Notify();
            }
            // pthread_mutex_unlock(&_mutex);
        }
        void Pop(T *out)
        {
            // pthread_mutex_lock(&_mutex);
            LockGuard lockguard(_mutex);
            while (IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                _consumer_cond.Wait(_mutex); // 在自己的条件变量下等
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            *out = _q.front();
            _q.pop();
            // 走到这，队列一定不为满
            if (_pwait_num)
            {
                std::cout << "唤醒生产者" << std::endl;
                //pthread_cond_signal(&_productor_cond);
                _productor_cond.Notify();
            }
            // pthread_mutex_unlock(&_mutex);
        }

        ~BlockQueue()
        {
        }

    private:
        std::queue<T> _q;     // 保存数据的容器，临界资源
        int _cap;             // bq最大容量
        Mutex _mutex;         // 互斥
        Cond _productor_cond; // 生产者条件变量
        Cond _consumer_cond;  // 消费者条件变量
        // 分别表示有多少个生产者和消费者去阻塞队列里等
        int _cwait_num;
        int _pwait_num;
    };
    // version 1
    //  static const int gcap = 10;
    //  template <class T>
    //  class BlockQueue
    //  {
    //  private:
    //      bool IsFull() { return _q.size() == _cap; }
    //      bool IsEmpty() { return _q.empty(); }

    // public:
    //     BlockQueue(int cap = gcap) : _cap(cap), _cwait_num(0), _pwait_num(0)
    //     {
    //         pthread_mutex_init(&_mutex, nullptr);
    //         pthread_cond_init(&_productor_cond, nullptr);
    //         pthread_cond_init(&_consumer_cond, nullptr);
    //     }
    //     void Equeue(const T &in)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         // 你想放就能放吗，生产数据是有条件的------阻塞队列不为满
    //         while (IsFull())
    //         {
    //             std::cout << "生产者进入等待..." << std::endl;
    //             _pwait_num++;
    //             pthread_cond_wait(&_productor_cond, &_mutex); // 我们在临界区中等待是必然的
    //             _pwait_num--;
    //             std::cout << "生产者被唤醒..." << std::endl;
    //         }
    //         // 走到这里，就是if(IsFUll())不满足 || 线程被唤醒
    //         _q.push(in); // 生产
    //         // 走到这，肯定有数据
    //         if (_cwait_num) // 阻塞队列里有消费者等待
    //         {
    //             std::cout << "唤醒消费者" << std::endl;
    //             pthread_cond_signal(&_consumer_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }
    //     void Pop(T *out)
    //     {
    //         pthread_mutex_lock(&_mutex);
    //         while (IsEmpty())
    //         {
    //             std::cout << "消费者进入等待..." << std::endl;
    //             _cwait_num++;
    //             pthread_cond_wait(&_consumer_cond, &_mutex); // 在自己的条件变量下等
    //             _cwait_num--;
    //             std::cout << "消费者被唤醒..." << std::endl;
    //         }
    //         *out = _q.front();
    //         _q.pop();
    //         // 走到这，队列一定不为满
    //         if (_pwait_num)
    //         {
    //             std::cout << "唤醒生产者" << std::endl;
    //             pthread_cond_signal(&_productor_cond);
    //         }
    //         pthread_mutex_unlock(&_mutex);
    //     }

    //     ~BlockQueue()
    //     {
    //         pthread_mutex_destroy(&_mutex);
    //         pthread_cond_destroy(&_productor_cond);
    //         pthread_cond_destroy(&_consumer_cond);
    //     }

    // private:
    //     std::queue<T> _q;               // 保存数据的容器，临界资源
    //     int _cap;                       // bq最大容量
    //     pthread_mutex_t _mutex;         // 互斥
    //     pthread_cond_t _productor_cond; // 生产者条件变量
    //     pthread_cond_t _consumer_cond;  // 消费者条件变量
    //     // 分别表示有多少个生产者和消费者去阻塞队列里等
    //     int _cwait_num;
    //     int _pwait_num;
    // };
}